Skip to content

fix(claude): bind Keychain reads to exact macOS account - #2

Merged
ruby-dlee merged 7 commits into
mainfrom
codex/exact-claude-keychain-account-v2
Jul 18, 2026
Merged

fix(claude): bind Keychain reads to exact macOS account#2
ruby-dlee merged 7 commits into
mainfrom
codex/exact-claude-keychain-account-v2

Conversation

@ruby-dlee

Copy link
Copy Markdown
Owner

Intent

Ship the Quota AXI exact-Claude-Keychain-account normalization required for Bridge cutover to the ruby-dlee/quota-axi fork only. Claude quota discovery must invoke fixed /usr/bin/security with both the exact service and OS-account selectors, resist hostile USER/LOGNAME/PATH, preserve non-Keychain fallbacks when the OS account is unavailable, and emit the exact Keychain account consistently in JSON and TOON auth-source and attempt contracts. OAuth-file attempts must not invent an account. This is the source for a future immutable 0.1.7 release consumed by Agent Fleet; it must not read or mutate live credentials, Desktop sessions, or provider homes during validation, must preserve the reviewed fixes already on this branch, and must never push to the upstream repository.

What Changed

  • Bind Claude Keychain queries to the fixed /usr/bin/security binary with exact service and passwd-derived macOS account selectors, while preserving OAuth-file and cached fallbacks when the account is unavailable.
  • Propagate the exact Keychain account through JSON and TOON auth-source and full-attempt output, without inventing accounts for OAuth-file attempts.
  • Document the normalized Keychain contract and add provider and CLI coverage for hostile environment variables, unavailable accounts, exact selectors, and output consistency.

Risk Assessment

✅ Low: The updated change cleanly omits account fields from OAuth-file TOON attempts while preserving exact Keychain account reporting, fixed-binary/account selectors, hostile-environment resistance, and non-Keychain fallbacks.

Testing

After retrying the initial Node 20 setup block with the already-installed Node 22 runtime, focused and full tests passed; an isolated real-CLI JSON/TOON flow demonstrated fixed-binary exact-account lookup under hostile environment variables, safe OAuth-file fallback, correct account propagation and omission, and output redaction. CLI transcripts replace screenshots because this change has no graphical UI.

Evidence: End-to-end JSON/TOON CLI transcript
# Quota AXI exact Claude Keychain account — end-to-end evidence

All commands below drove the real CLI command, Claude provider, JSON renderer, and TOON renderer. The macOS account, Keychain subprocess, credential blob, and Anthropic HTTP responses were synthetic test fixtures; no live provider home, credential, Desktop session, or network endpoint was read.

## 1. Hostile environment cannot redirect the Keychain lookup

Environment: `USER=hostile-user LOGNAME=hostile-logname PATH=/hostile/bin`

Command: `quota-axi auth --provider claude --json` (non-secret presence check)

`` `json
[
  {
    "source": "oauth-file",
    "status": "missing",
    "path": "/var/folders/y_/bfdbj_vx20l9b9tw7crgkzwm0000gn/T/no-mistakes-evidence/01KXTSRD4CGY9BMPDW3QFP246R/runtime/keychain/home/.claude/.credentials.json"
  },
  {
    "source": "keychain",
    "status": "skipped",
    "error": "keychain_prompt_required",
    "credentialPresent": true,
    "account": "bridge-os-account"
  }
]
`` `

Command: `quota-axi --allow-keychain-prompt auth --provider claude --json`

`` `json
[
  {
    "source": "oauth-file",
    "status": "missing",
    "path": "/var/folders/y_/bfdbj_vx20l9b9tw7crgkzwm0000gn/T/no-mistakes-evidence/01KXTSRD4CGY9BMPDW3QFP246R/runtime/keychain/home/.claude/.credentials.json"
  },
  {
    "source": "keychain",
    "status": "available",
    "account": "bridge-os-account"
  }
]
`` `

Observed subprocess calls:

`` `json
[
  {
    "file": "/usr/bin/security",
    "args": [
      "find-generic-password",
      "-s",
      "Claude Code-credentials",
      "-a",
      "bridge-os-account"
    ],
    "timeoutMs": 5000
  },
  {
    "file": "/usr/bin/security",
    "args": [
      "find-generic-password",
      "-s",
      "Claude Code-credentials",
      "-a",
      "bridge-os-account",
      "-w"
    ],
    "timeoutMs": 60000
  },
  {
    "file": "/usr/bin/security",
    "args": [
      "find-generic-password",
      "-s",
      "Claude Code-credentials",
      "-a",
      "bridge-os-account",
      "-w"
    ],
    "timeoutMs": 60000
  },
  {
    "file": "/usr/bin/security",
    "args": [
      "find-generic-password",
      "-s",
      "Claude Code-credentials",
      "-a",
      "bridge-os-account",
      "-w"
    ],
    "timeoutMs": 60000
  },
  {
    "file": "/usr/bin/security",
    "args": [
      "find-generic-password",
      "-s",
      "Claude Code-credentials",
      "-a",
      "bridge-os-account",
      "-w"
    ],
    "timeoutMs": 60000
  }
]
`` `

## 2. Exact account reaches JSON and TOON contracts

Command: `quota-axi --provider claude --json --full --allow-keychain-prompt`

`` `json
{
  "state": {
    "status": "fresh",
    "stale": false,
    "refreshedAt": "2026-07-18T14:43:53.716Z",
    "sourcesTried": [
      "oauth-file",
      "keychain",
      "oauth",
      "oauth-profile"
    ]
  },
  "attempts": [
    {
      "source": "oauth-file",
      "status": "skipped",
      "error": "credentials_missing"
    },
    {
      "source": "keychain",
      "status": "success",
      "account": "bridge-os-account"
    },
    {
      "source": "oauth",
      "status": "success"
    },
    {
      "source": "oauth-profile",
      "status": "success"
    }
  ]
}
`` `

Command: `quota-axi --provider claude --full --allow-keychain-prompt`

`` `text
bin: quota-axi
description: Report local agent-provider quota windows for routing-aware agents
generatedAt: "2026-07-18T14:43:53.718Z"
providers[1]{provider,plan,source,status,refreshedAt}:
  claude,pro,oauth,fresh,"2026-07-18T14:43:53.718Z"
windows[1]{provider,id,label,percentRemaining,resetsAt,state}:
  claude,five_hour,session,88,"2035-01-01T05:00:00.000Z",fresh
accounts[1]{provider,email,organization,accountId,identityStatus}:
  claude,[email protected],Bridge Fixture,synthetic-account-id,verified
attempts[4]:
  - provider: claude
    source: oauth-file
    status: skipped
    error: credentials_missing
  - provider: claude
    source: keychain
    status: success
    error: none
    account: bridge-os-account
  - provider: claude
    source: oauth
    status: success
    error: none
  - provider: claude
    source: oauth-profile
    status: success
    error: none
help[3]:
  Run `quota-axi --provider claude --json` for JSON output
  Run `quota-axi --full` to include account and source-attempt details
  Run `quota-axi auth` to inspect local auth source availability without printing secrets
`` `

Command: `quota-axi auth --provider claude --allow-keychain-prompt`

`` `text
bin: quota-axi
description: Inspect local quota auth sources without printing secret values
auth[2]{provider,source,path,status,error,account}:
  claude,oauth-file,~/.claude/.credentials.json,missing,none,none
  claude,keychain,none,available,none,bridge-os-account
help[1]:
  Run `quota-axi --allow-keychain-prompt auth` to permit macOS Keychain access
`` `

## 3. Missing OS account preserves the OAuth-file fallback

Command: `quota-axi auth --provider claude --json`

`` `json
[
  {
    "source": "oauth-file",
    "status": "available",
    "path": "/var/folders/y_/bfdbj_vx20l9b9tw7crgkzwm0000gn/T/no-mistakes-evidence/01KXTSRD4CGY9BMPDW3QFP246R/runtime/fallback/home/.claude/.credentials.json"
  },
  {
    "source": "keychain",
    "status": "skipped",
    "error": "keychain_account_unavailable"
  }
]
`` `

Command: `quota-axi --provider claude --json --full`

`` `json
{
  "state": {
    "status": "fresh",
    "stale": false,
    "refreshedAt": "2026-07-18T14:43:53.732Z",
    "sourcesTried": [
      "keychain",
      "oauth",
      "oauth-profile"
    ]
  },
  "attempts": [
    {
      "source": "keychain",
      "status": "skipped",
      "error": "keychain_account_unavailable"
    },
    {
      "source": "oauth",
      "status": "success"
    },
    {
      "source": "oauth-profile",
      "status": "success"
    }
  ]
}
`` `

Security subprocess calls: `0`.

## 4. OAuth-file attempts do not invent an account

Command: `quota-axi --provider claude --json --full` with an expired synthetic OAuth file and unavailable OS account.

`` `json
[
  {
    "source": "oauth-file",
    "status": "skipped",
    "error": "credentials_expired"
  },
  {
    "source": "keychain",
    "status": "skipped",
    "error": "keychain_account_unavailable"
  }
]
`` `

Command: `quota-axi --provider claude --full`

`` `text
bin: quota-axi
description: Report local agent-provider quota windows for routing-aware agents
generatedAt: "2026-07-18T14:43:53.755Z"
providers[1]{provider,plan,source,status,refreshedAt}:
  claude,unknown,unavailable,auth_required,none
windows[0]:
accounts[1]{provider,email,organization,accountId,identityStatus}:
  claude,hidden,none,none,unknown
attempts[2]{provider,source,status,error}:
  claude,oauth-file,skipped,credentials_expired
  claude,keychain,skipped,keychain_account_unavailable
help[3]:
  Run `quota-axi --provider claude --json` for JSON output
  Run `quota-axi --full` to include account and source-attempt details
  Run `quota-axi auth` to inspect local auth source availability without printing secrets
`` `

The JSON OAuth-file attempt has no `account` property, and the TOON attempts table has no `account` column because no attempt has a known account.

## Isolation audit

`` `json
{
  "hostileEnvironment": {
    "USER": "hostile-user",
    "LOGNAME": "hostile-logname",
    "PATH": "/hostile/bin"
  },
  "osAccount": "bridge-os-account",
  "invocations": [
    {
      "file": "/usr/bin/security",
      "args": [
        "find-generic-password",
        "-s",
        "Claude Code-credentials",
        "-a",
        "bridge-os-account"
      ],
      "timeoutMs": 5000
    },
    {
      "file": "/usr/bin/security",
      "args": [
        "find-generic-password",
        "-s",
        "Claude Code-credentials",
        "-a",
        "bridge-os-account",
        "-w"
      ],
      "timeoutMs": 60000
    },
    {
      "file": "/usr/bin/security",
      "args": [
        "find-generic-password",
        "-s",
        "Claude Code-credentials",
        "-a",
        "bridge-os-account",
        "-w"
      ],
      "timeoutMs": 60000
    },
    {
      "file": "/usr/bin/security",
      "args": [
        "find-generic-password",
        "-s",
        "Claude Code-credentials",
        "-a",
        "bridge-os-account",
        "-w"
      ],
      "timeoutMs": 60000
    },
    {
      "file": "/usr/bin/security",
      "args": [
        "find-generic-password",
        "-s",
        "Claude Code-credentials",
        "-a",
        "bridge-os-account",
        "-w"
      ],
      "timeoutMs": 60000
    }
  ],
  "fallbackInvocations": [],
  "expiredFileInvocations": [],
  "checks": {
    "everyInvocationUsesFixedBinary": true,
    "everyInvocationUsesExactServiceAndAccount": true,
    "noSecurityInvocationWhenAccountUnavailable": true,
    "syntheticTokenAbsentFromAllCliOutput": true
  }
}
`` `
Evidence: Security invocation and isolation audit
{
  "hostileEnvironment": {
    "USER": "hostile-user",
    "LOGNAME": "hostile-logname",
    "PATH": "/hostile/bin"
  },
  "osAccount": "bridge-os-account",
  "invocations": [
    {
      "file": "/usr/bin/security",
      "args": [
        "find-generic-password",
        "-s",
        "Claude Code-credentials",
        "-a",
        "bridge-os-account"
      ],
      "timeoutMs": 5000
    },
    {
      "file": "/usr/bin/security",
      "args": [
        "find-generic-password",
        "-s",
        "Claude Code-credentials",
        "-a",
        "bridge-os-account",
        "-w"
      ],
      "timeoutMs": 60000
    },
    {
      "file": "/usr/bin/security",
      "args": [
        "find-generic-password",
        "-s",
        "Claude Code-credentials",
        "-a",
        "bridge-os-account",
        "-w"
      ],
      "timeoutMs": 60000
    },
    {
      "file": "/usr/bin/security",
      "args": [
        "find-generic-password",
        "-s",
        "Claude Code-credentials",
        "-a",
        "bridge-os-account",
        "-w"
      ],
      "timeoutMs": 60000
    },
    {
      "file": "/usr/bin/security",
      "args": [
        "find-generic-password",
        "-s",
        "Claude Code-credentials",
        "-a",
        "bridge-os-account",
        "-w"
      ],
      "timeoutMs": 60000
    }
  ],
  "fallbackInvocations": [],
  "expiredFileInvocations": [],
  "checks": {
    "everyInvocationUsesFixedBinary": true,
    "everyInvocationUsesExactServiceAndAccount": true,
    "noSecurityInvocationWhenAccountUnavailable": true,
    "syntheticTokenAbsentFromAllCliOutput": true
  }
}
Evidence: Raw full JSON quota output
{
  "generatedAt": "2026-07-18T14:43:53.716Z",
  "schemaVersion": 2,
  "providers": [
    {
      "provider": "claude",
      "label": "Claude",
      "source": "oauth",
      "plan": "pro",
      "account": {
        "accountId": "synthetic-account-id",
        "email": "[email protected]",
        "organization": "Bridge Fixture",
        "identityStatus": "verified"
      },
      "windows": [
        {
          "id": "five_hour",
          "label": "session",
          "kind": "session",
          "percentUsed": 12,
          "resetsAt": "2035-01-01T05:00:00.000Z",
          "percentRemaining": 88
        }
      ],
      "attempts": [
        {
          "source": "oauth-file",
          "status": "skipped",
          "error": "credentials_missing"
        },
        {
          "source": "keychain",
          "status": "success",
          "account": "bridge-os-account"
        },
        {
          "source": "oauth",
          "status": "success"
        },
        {
          "source": "oauth-profile",
          "status": "success"
        }
      ],
      "state": {
        "status": "fresh",
        "stale": false,
        "refreshedAt": "2026-07-18T14:43:53.716Z",
        "sourcesTried": [
          "oauth-file",
          "keychain",
          "oauth",
          "oauth-profile"
        ]
      }
    }
  ]
}
Evidence: Raw full TOON quota output
bin: quota-axi
description: Report local agent-provider quota windows for routing-aware agents
generatedAt: "2026-07-18T14:43:53.718Z"
providers[1]{provider,plan,source,status,refreshedAt}:
  claude,pro,oauth,fresh,"2026-07-18T14:43:53.718Z"
windows[1]{provider,id,label,percentRemaining,resetsAt,state}:
  claude,five_hour,session,88,"2035-01-01T05:00:00.000Z",fresh
accounts[1]{provider,email,organization,accountId,identityStatus}:
  claude,[email protected],Bridge Fixture,synthetic-account-id,verified
attempts[4]:
  - provider: claude
    source: oauth-file
    status: skipped
    error: credentials_missing
  - provider: claude
    source: keychain
    status: success
    error: none
    account: bridge-os-account
  - provider: claude
    source: oauth
    status: success
    error: none
  - provider: claude
    source: oauth-profile
    status: success
    error: none
help[3]:
  Run `quota-axi --provider claude --json` for JSON output
  Run `quota-axi --full` to include account and source-attempt details
  Run `quota-axi auth` to inspect local auth source availability without printing secrets

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed ✅
  • 🚨 src/render.ts:123 - The full TOON renderer sets account to the literal "none" for every account-less attempt. An OAuth-file attempt therefore omits account in JSON but emits account: "none" in TOON, contradicting “OAuth-file attempts must not invent an account” and making the contracts disagree. Confirm none as an approved sentinel or omit the field for non-Keychain attempts.

🔧 Fix: Omit invented OAuth-file accounts from TOON attempts
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • Target inspection: git branch --show-current && git status --short && git rev-parse HEAD plus git diff/git log from base 962844a52d611c5366fa535582fb72029dcd029c to target
  • Initial setup attempt: pnpm exec vitest run test/providers/claude-auth.test.ts test/cli.test.ts (stopped before tests because Node 20 cannot run pnpm 11.1.1)
  • Focused suites: PATH="$HOME/.nvm/versions/node/v22.22.0/bin:$PATH" pnpm exec vitest run test/providers/claude-auth.test.ts test/cli.test.ts
  • Synthetic end-to-end evidence: PATH="$HOME/.nvm/versions/node/v22.22.0/bin:$PATH" pnpm exec vitest run test/exact-keychain-validation.evidence.test.ts --reporter=verbose
  • Full regression suite: PATH="$HOME/.nvm/versions/node/v22.22.0/bin:$PATH" pnpm test
  • Manual evidence audit: inspected captured JSON/TOON and verified fixed /usr/bin/security, exact -s/-a selectors, zero security calls when the OS account is unavailable, OAuth-file account omission, and synthetic-token redaction
  • Cleanup verification: removed the transient evidence harness, then ran git status --short && git rev-parse HEAD
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@ruby-dlee
ruby-dlee merged commit d61cbcf into main Jul 18, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant